package hdf.utils;

import ncsa.hdf.object.Attribute;
import ncsa.hdf.object.Dataset;
import ncsa.hdf.object.FileFormat;
import ncsa.hdf.object.Group;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Ania on 30.03.14.
 */
public class HdfFileHelper {
    public static void closeFile(FileFormat file) {
        try {
            file.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static FileFormat openFile(String filename, FileFormat fileFormat) {
        if (fileFormat == null) {
            return null;
        }
        try {
            FileFormat testFile = fileFormat.open(filename, FileFormat.READ);
            if (testFile == null) {
                return null;
            }

            testFile.open();
            return testFile;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String datasetInfo(Dataset dataset, String filename, FileFormat fileFormat) {
        if (dataset == null)
            return "";
        try {
            FileFormat file = openFile(filename, fileFormat);
            dataset.getMetadata();
            dataset.getData();
            closeFile(file);
        } catch (Exception e) {
            e.printStackTrace();
        }
        StringBuilder builder = new StringBuilder(dataset.getName()).append(" [");
        long[] dims = dataset.getDims();
        for (int i = 0; i < dims.length; i++) {
            builder.append(dims[i]);
            if (i < dims.length - 1) {
                builder.append(", ");
            }
        }
        builder.append("]");
        builder.append("\n");

        try {
            if (dataset.getMetadata() == null) return builder.toString();
            for (Object attrObj : dataset.getMetadata()) {
                Attribute attr = (Attribute) attrObj;
                builder.append("\t").append(attr.getName()).append(": ");
                for (Object valueObj : convertToObjectArray(attr.getValue())) {
                    builder.append(valueObj).append("; ");
                }
                builder.append("\n");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return builder.toString();
    }

    public static Object[] convertToObjectArray(Object array) {
        Class ofArray = array.getClass().getComponentType();
        if (ofArray.isPrimitive()) {
            List ar = new ArrayList();
            int length = Array.getLength(array);
            for (int i = 0; i < length; i++) {
                ar.add(Array.get(array, i));
            }
            return ar.toArray();
        } else {
            return (Object[]) array;
        }
    }

    public static Dataset getDatasetByFullName(FileFormat file, String fullName) {
        TreeNode rootNode = file.getRootNode();
        Group root = (Group) ((DefaultMutableTreeNode) rootNode).getUserObject();
        Dataset dataset = findDatasetByName(root, fullName);
        return dataset;
    }

    private static Dataset findDatasetByName(Group g, String fullName) {
        if (g == null)
            return null;
        List members = g.getMemberList();
        for (Object member : members) {
            if (member instanceof Dataset) {
                Dataset dataset = (Dataset) member;
                if (fullName.equals(dataset.getFullName())) {
                    return dataset;
                }
            } else if (member instanceof Group) {
                Dataset dataset = findDatasetByName((Group) member, fullName);
                if (dataset != null) return dataset;
            }
        }
        return null;
    }

    public static double[] getValueRange(Dataset dataset) {
        double[] range = new double[]{0.0, 160000.0};
        try {
            short[] data = (short[]) (dataset.read());
            double min = 0, max = 0;
            if (data != null && data.length > 0) {
                min = data[0];
                max = data[0];
                if (data.length > 1) {
                    for (int i = 1; i < data.length; i++) {
                        if (data[i] > max)
                            max = data[i];
                        else if (data[i] < min) {
                            min = data[i];
                        }
                    }
                }
                range[0] = min;
                range[1] = max;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return range;
    }
}
